using System;
using System.Collections;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace Patchy
{
    class ParseFile
    {
        private string mInputFile;

        public ParseFile(string inputFile)
        {
            mInputFile = inputFile;
        }

        public GroupHolder ReadFile()
        {
            SortedList mGroups = null;
            TextReader tr = null;
            MyGroup group = null;

            try
            {
                tr = new StreamReader(mInputFile);
                string str = "";
                int counter = 0;
                bool hasDir = false;//sanity check
                mGroups = new SortedList(StringComparer.OrdinalIgnoreCase);

                while ((str = tr.ReadLine()) != null)
                {
                    counter++;
                    if (str.Trim() == "")
                    {
                        continue;
                    }
                    else if (hasDir && (str.StartsWith("\t") || str.StartsWith(" ")) && !str.TrimEnd().EndsWith(":")) //file
                    {
                        group.AddFile(strippedName(str, true), normalisedName(str, true));
                    }
                    else if (!str.StartsWith("\t") && !str.StartsWith(" ") && str.TrimEnd().EndsWith(":")) //directory
                    {
                        hasDir = true;
                        str = normalisedName(str, false);
                        if (mGroups.ContainsKey(str))
                        {
                            group = (MyGroup)mGroups[str];
                        }
                        else
                        {
                            group = new MyGroup(strippedName(str, false));
                            mGroups.Add(str, group);
                        }
                    }
                    else
                    {
                        MessageBox.Show("Parsing died on line " + counter + ".");
                        mGroups = null;
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Opening \"" + mInputFile + "\" failed:\n" + ex.Message);
                mGroups = null;
            }
            finally
            {
                if (tr != null)
                {
                    tr.Close();
                }
            }
            return new GroupHolder(mGroups);
        }
        
        /// <summary>
        /// Return the name converted to a local file, without any weirdness.
        /// \\srv-remote\d$\Inetpub\wwwroot\bin:    -> d:\Inetpub\wwwroot\bin\
        /// \\srv-remote\Program\file               -> C:\Program\file
        /// \\srv-remote\Program\file:              -> C:\Program\file\
        /// C::                                     -> C:\
        /// hello                                   -> C:\hello
        /// </summary>
        private string normalisedName(string str, bool isFile)
        {
            char sep = '\\';
            str = str.Trim().TrimEnd(":$\\/".ToCharArray()).Replace('$', ':').Replace('/', sep);
            if (str.IndexOf(':') == -1)  // \\foobar\file or \\foobar -> \\foobar\C:\file or \\foobar\c: (default to C:)
            {
                int idx = str.IndexOf(sep, 3);
                if (idx == -1 && !isFile)
                {
                    str = "C:\\";
                }
                else if (idx == -1)
                {
                    str = "C:\\" + str;
                }
                else
                {
                    str = "C:\\" + str.Substring(idx);
                }
            }
            string dup = "\\\\";
            while (str.IndexOf(dup) != -1)
            {
                str = str.Replace(dup, sep.ToString());
            }
            str = str.Substring(str.IndexOf(':') - 1);
            str = isFile ? str : str.TrimEnd(sep) + sep;
            return str;
        }

        /* return the original name, only without the ':' or tabs from the patchy file */
        private string strippedName(string str, bool isFile)
        {
            str = str.Trim();
            return isFile ? str.Trim() : str.Trim().TrimEnd(':');
        }
    }
}
